/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */
package com.gos.creator.service.impl;

import com.gos.creator.constance.NormalName;
import com.gos.creator.domain.DataBase;
import com.gos.creator.domain.PrimaryKey;
import com.gos.creator.domain.Table;
import com.gos.creator.domain.TableField;
import com.gos.creator.mapper.MySqlMapper;
import com.gos.creator.service.MySqlCreatorService;
import com.gos.creator.util.NameParser;
import com.gos.creator.util.VelocityEngineUtil;
import org.apache.velocity.Template;
import org.apache.velocity.VelocityContext;
import org.apache.velocity.context.Context;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.Writer;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.List;
import java.util.Locale;

/**
 * @author Xue Liang
 */
public class MySqlCreatorServiceImpl implements MySqlCreatorService {
    private static final Logger LOGGER = LoggerFactory.getLogger(MySqlCreatorServiceImpl.class);

    private static final String TEMPLATE_BASE = "/com/gos/creator/template";

    @Override
    public boolean createEntities(DataBase dataBase, String dir, String packageName) {
        String packageDirectory = dir + File.separator + packageName.replace(".", File.separator);
        File target = new File(packageDirectory);
        if (!target.exists()) {
            if (!target.mkdirs()) {
                return false;
            }
        }
        String here = this.getClass().getResource(TEMPLATE_BASE + "/Entity.vm").toString().replace("file:", "");

        Template template = VelocityEngineUtil.getTemplate(new File(here));
        for (Table table : dataBase.getTables()) {
            File sourceCodeFile = new File(packageDirectory + File.separator + table.getEntityClassName() + ".java");
            try (Writer writer = new FileWriter(sourceCodeFile)) {
                Context context = new VelocityContext();
                context.put(NormalName.ENTITY_PACKAGE_NAME.getValue(), packageName);
                context.put(NormalName.Table.getValue(), table);
                DateFormat formatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
                context.put(NormalName.Now.getValue(), formatter.format(Calendar.getInstance(Locale.PRC).getTime()));
                if (template != null) {
                    template.merge(context, writer);
                }
            } catch (IOException e) {
                LOGGER.error("生成实体代码时发生了异常:", e);
            }
        }
        return true;
    }

    @Override
    public boolean createDao(DataBase dataBase, String dir, String entityPackageName, String daoPackageName) {
        String packageDirectory = dir + File.separator + daoPackageName.replace(".", File.separator);
        File target = new File(packageDirectory);
        if (!target.exists()) {
            if (!target.mkdirs()) {
                return false;
            }
        }
        String here = this.getClass().getResource(TEMPLATE_BASE + "/AbstractDao.vm").toString().replace("file:", "");
        Template template = VelocityEngineUtil.getTemplate(new File(here));
        for (Table table : dataBase.getTables()) {
            File sourceCodeFile = new File(packageDirectory + "/Abstract" + table.getEntityClassName() + "Dao.java");
            try (Writer writer = new FileWriter(sourceCodeFile)) {
                Context context = new VelocityContext();
                context.put(NormalName.ENTITY_PACKAGE_NAME.getValue(), entityPackageName);
                context.put(NormalName.DAO_PACKAGE_NAME.getValue(), daoPackageName);
                context.put(NormalName.Table.getValue(), table);
                PrimaryKey pk = table.getPrimaryKey();
                if (pk != null) {
                    List<TableField> keys = pk.getKey();
                    if (keys != null) {
                        for (TableField tf : keys) {
                            Boolean isAutoIncrement = tf.getIsAutoIncrement();
                            if (isAutoIncrement != null && isAutoIncrement.booleanValue()) {
                                String f = tf.getDataBaseFieldDataType();
                                f = MySqlMapper.getInstance().toJavaType(f).toLowerCase();
                                context.put(NormalName.AUTO_INCREMENT_FIELD_DATA_BASE_DATA_TYPE.getValue(), "int".equalsIgnoreCase(f) ? "int" : "long");
                                break;
                            }
                        }
                    }
                }
                DateFormat formatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
                context.put(NormalName.Now.getValue(), formatter.format(Calendar.getInstance(Locale.PRC).getTime()));
                if (template != null) {
                    template.merge(context, writer);
                }
            } catch (IOException e) {
                LOGGER.error("生成数据访问层代码时发生了异常:", e);
            }
        }

        here = this.getClass().getResource(TEMPLATE_BASE + "/Dao.vm").toString().replace("file:", "");
        template = VelocityEngineUtil.getTemplate(new File(here));
        for (Table table : dataBase.getTables()) {
            File sourceCodeFile = new File(packageDirectory + File.separator + table.getEntityClassName() + "Dao.java");
            try (Writer writer = new FileWriter(sourceCodeFile)) {
                Context context = new VelocityContext();
                context.put(NormalName.ENTITY_PACKAGE_NAME.getValue(), entityPackageName);
                context.put(NormalName.DAO_PACKAGE_NAME.getValue(), daoPackageName);
                context.put(NormalName.Table.getValue(), table);
                DateFormat formatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
                context.put(NormalName.Now.getValue(), formatter.format(Calendar.getInstance(Locale.PRC).getTime()));
                if (template != null) {
                    template.merge(context, writer);
                }
            } catch (IOException e) {
                LOGGER.error("生成数据访问层代码时发生了异常:", e);
            }
        }


        here = this.getClass().getResource(TEMPLATE_BASE + "/SqlBuilder.vm").toString().replace("file:", "");
        template = VelocityEngineUtil.getTemplate(new File(here));
        File sourceCodeFile = new File(packageDirectory + File.separator + "SqlBuilder.java");
        try (Writer writer = new FileWriter(sourceCodeFile)) {
            Context context = new VelocityContext();
            context.put(NormalName.ENTITY_PACKAGE_NAME.getValue(), entityPackageName);
            context.put(NormalName.DAO_PACKAGE_NAME.getValue(), daoPackageName);
            DateFormat formatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
            context.put(NormalName.Now.getValue(), formatter.format(Calendar.getInstance(Locale.PRC).getTime()));
            if (template != null) {
                template.merge(context, writer);
            }
        } catch (IOException e) {
            LOGGER.error("生成数据访问层代码时发生了异常:", e);
        }
        return true;
    }

    @Override
    public boolean createService(DataBase dataBase, String dir, String entityPackageName, String daoPackageName,
                                 String servicePackageName) {
        String packageDirectory = dir + File.separator + servicePackageName.replace(".", File.separator);
        File target = new File(packageDirectory);
        if (!target.exists() && !target.mkdirs()) {
            return false;
        }
        String here = this.getClass().getResource(TEMPLATE_BASE + "/Service.vm").toString().replace("file:", "");

        Template template = VelocityEngineUtil.getTemplate(new File(here));
        for (Table table : dataBase.getTables()) {
            File sourceCodeFile = new File(packageDirectory + File.separator + table.getEntityClassName() + "Service.java");
            try (Writer writer = new FileWriter(sourceCodeFile)) {
                Context context = new VelocityContext();
                context.put("dao", NameParser.toCamel(table.getEntityClassName() + "Dao", true));
                context.put(NormalName.ENTITY_PACKAGE_NAME.getValue(), entityPackageName);
                context.put(NormalName.DAO_PACKAGE_NAME.getValue(), daoPackageName);
                context.put(NormalName.ServicePackageName.getValue(), servicePackageName);
                context.put(NormalName.Table.getValue(), table);
                DateFormat formatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
                context.put(NormalName.Now.getValue(), formatter.format(Calendar.getInstance(Locale.PRC).getTime()));
                if (template != null) {
                    template.merge(context, writer);
                }
            } catch (IOException e) {
                LOGGER.error("生成业务层代码时发生了异常:", e);
            }
        }


        packageDirectory = (dir + File.separator + servicePackageName + "/impl").replace(".", File.separator);
        target = new File(packageDirectory);
        if (!target.exists() && !target.mkdirs()) {
            return false;
        }
        here = this.getClass().getResource(TEMPLATE_BASE + "/ServiceImpl.vm").toString().replace("file:", "");

        template = VelocityEngineUtil.getTemplate(new File(here));
        for (Table table : dataBase.getTables()) {
            File sourceCodeFile = new File(packageDirectory + File.separator + table.getEntityClassName() + "ServiceImpl.java");
            try (Writer writer = new FileWriter(sourceCodeFile)) {
                Context context = new VelocityContext();
                context.put("dao", NameParser.toCamel(table.getEntityClassName() + "Dao", true));
                context.put(NormalName.ENTITY_PACKAGE_NAME.getValue(), entityPackageName);
                context.put(NormalName.DAO_PACKAGE_NAME.getValue(), daoPackageName);
                context.put(NormalName.ServicePackageName.getValue(), servicePackageName);
                context.put(NormalName.Table.getValue(), table);
                DateFormat formatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
                context.put(NormalName.Now.getValue(), formatter.format(Calendar.getInstance(Locale.PRC).getTime()));
                if (template != null) {
                    template.merge(context, writer);
                }
            } catch (IOException e) {
                LOGGER.error("生成数据访问层代码时发生了异常:", e);
            }
        }
        return true;
    }
}
